import requests
from bs4 import BeautifulSoup
import pandas as pd
import time
import os
from view import areaView, priceView, distanceView, timeView
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error


def getUrls():
    urls = []
    baseUrl = "https://www.che168.com/china/a0_0msdgscncgpi1ltocsp"
    for i in range(1, 6):  # 限制5页
        url = "{}{}exx0/".format(baseUrl, i)
        urls.append(url)
    return urls


headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0"
}


def gethtmltext(url):
    try:
        r = requests.get(url, headers=headers)
        r.raise_for_status()
        return r.text
    except:
        return ""


def ParsePage(html):
    if html == '':
        return
    soup = BeautifulSoup(html, features="html.parser")
    info = soup.select("div .cards-bottom")
    data = []

    for item in info:
        name = item.contents[1].text.strip()
        msgMix = str(item.contents[3].text).split("／")
        if len(msgMix) != 4:
            continue

        price = item.contents[5].contents[0].contents[0].text.strip()
        if price == '抢购价':
            continue

        mileage = msgMix[0].replace("万公里", "").strip()
        year = msgMix[1].split("-")[0].strip()
        if year == '未上牌':
            year = 2024

        location = msgMix[2].strip()
        membership = msgMix[3].strip()

        # 数据预处理
        try:
            mileage = float(mileage)
            year = int(year)
            price = float(price.replace('万', '')) * 10000  # 转换为元
        except ValueError:
            continue

        data.append([name, mileage, year, location, membership, price])

    return data


def getData():
    if os.path.exists('data.csv'):
        os.remove('data.csv')

    columns = ["名称", "里程", "时间", "地址", "会员", "价格"]
    df = pd.DataFrame([], columns=columns)

    df.to_csv("data.csv", mode="a", header=True, index=False, encoding="utf-8_sig")

    urls = getUrls()
    all_data = []

    for i in range(len(urls)):
        html = gethtmltext(urls[i])
        data = ParsePage(html)
        if data:  # 如果解析到了数据
            all_data.extend(data)
        print(f"第{i + 1}页解析完毕！")
        time.sleep(2)

    # 将所有数据转换为 DataFrame 并进行预处理
    df_all = pd.DataFrame(all_data, columns=columns)

    # 处理空值与缺省值
    df_all.fillna({
        '里程': 0.0,
        '时间': 2024,
        '地址': '未知',
        '会员': '无',
        '价格': 0.0
    }, inplace=True)

    # 确保数值字段是正确的类型
    df_all['里程'] = pd.to_numeric(df_all['里程'], errors='coerce')
    df_all['时间'] = pd.to_numeric(df_all['时间'], errors='coerce')
    df_all['价格'] = pd.to_numeric(df_all['价格'], errors='coerce')

    # 将类别数据转换为数值（用于后续分析）
    df_all['地址'] = df_all['地址'].astype('category').cat.codes
    df_all['会员'] = df_all['会员'].astype('category').cat.codes

    # 写入 CSV 文件
    df_all.to_csv("data.csv", mode="w", index=False, encoding="utf-8_sig")
    print("所有数据写入完毕！")


def draw():
    if os.path.exists('data.csv'):
        df = pd.read_csv("data.csv")
        df = df.dropna()
        areaView(df)
        priceView(df)
        distanceView(df)
        timeView(df)


def predict():
    if not os.path.exists('data.csv'):
        print("数据文件不存在，请先运行 getData() 获取数据。")
        return

    df = pd.read_csv('data.csv')

    # 排序、筛选、最大最小值应用
    df_sorted_by_price = df.sort_values(by='价格', ascending=False)
    df_filtered = df[df['里程'] > 0]
    max_price = df['价格'].max()
    min_price = df['价格'].min()

    print("按价格降序排列的前5条记录：")
    print(df_sorted_by_price.head())
    print("\n筛选出行驶里程大于0公里的记录：")
    print(df_filtered.head())
    print(f"\n最高价格: {max_price}, 最低价格: {min_price}")

    # 构建线性回归模型并训练预测
    X = df[['里程', '时间', '地址', '会员']]
    y = df['价格']

    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
    model = LinearRegression()
    model.fit(X_train, y_train)

    y_pred = model.predict(X_test)
    mse = mean_squared_error(y_test, y_pred)

    print(f"\nMean Squared Error: {mse}")
    print("预测价格：", y_pred[:5])
    print("实际价格：", y_test[:5].values)


if __name__ == "__main__":
    getData()
    draw()
    predict()